home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 PPC / Demo / www / www.py < prev    next >
Text File  |  1996-05-19  |  10KB  |  440 lines

  1. #! /usr/local/bin/python
  2.  
  3. # A simple text-based WWW client.
  4.  
  5. # This is not intended to compete with WWW's LineMode browser, but to
  6. # have an easily modifiable WWW browser, and also to test various
  7. # components like the formatters and protocol interfaces.
  8.  
  9.  
  10. import sys
  11. import os
  12. import string
  13. import getopt
  14. from cmd import Cmd
  15.  
  16. import fmt
  17. import htmllib
  18. import wwwlib
  19. import wwwutil
  20.  
  21.  
  22. PAGE_WIDTH = 80                # Page width (for formatter)
  23.  
  24.  
  25. # Default locations of logging files
  26. PLACES = '.wwwplaces'
  27. HISTORY = '.wwwhistory'
  28. BOOKMARKS = '.wwwbookmarks'
  29.  
  30.  
  31. # Main program
  32. def main():
  33.     #
  34.     places_file = ''
  35.     history_file = ''
  36.     bookmarks_file = ''
  37.     #
  38.     try:
  39.         opts, args = getopt.getopt(sys.argv[1:], 'b:h:p:')
  40.     except getopt.error, msg:
  41.         sys.stdout = sys.stderr
  42.         print msg
  43.         print 'usage: www [-b file] [-h file] [-p file] [docaddr]'
  44.         print '-b file: bookmarks file, default ~/' + BOOKMARKS
  45.         print '-h file: history file, default ~/' + HISTORY
  46.         print '-p file: places file, default ~/' + PLACES
  47.         print 'docaddr: document address, e.g. scheme://host:port/path'
  48.         print 'system default:', wwwutil.system_home
  49.         if wwwutil.user_home <> wwwutil.system_home:
  50.             print 'user default:', wwwutl.user_home
  51.         print 'user default settable with $WWW_HOME'
  52.         sys.exit(2)
  53.     #
  54.     for o, a in opts:
  55.         if o == '-b': bookmarks_file = a
  56.         if o == '-h': history_file = a
  57.         if o == '-p': places_file = a
  58.     #
  59.     if args:
  60.         if len(args) > 1:
  61.             print 'Too many files -- first one used'
  62.         addr = args[0]
  63.     else:
  64.         addr = ''
  65.     #
  66.     x = WWWCmd()
  67.     #
  68.     places = wwwutil.load_file(places_file, PLACES)
  69.     if places:
  70.         x.places = places
  71.     #
  72.     history = wwwutil.load_file(history_file, HISTORY)
  73.     if history:
  74.         if not addr:
  75.             addr = history[-1]
  76.             history = history[:-1]
  77.         x.history = history
  78.     #
  79.     bookmarks = wwwutil.load_file(bookmarks_file, BOOKMARKS)
  80.     if bookmarks is None: bookmarks = []
  81.     if wwwutil.user_home and wwwutil.user_home not in bookmarks:
  82.         bookmarks.insert(0, wwwutil.user_home)
  83.     if wwwutil.system_home and wwwutil.system_home not in bookmarks:
  84.         bookmarks.insert(0, wwwutil.system_home)
  85.     if bookmarks:
  86.         x.bookmarks = bookmarks
  87.     #
  88.     if not addr:
  89.         addr = wwwutil.user_home
  90.     ok = x.setaddr(addr)
  91.     if not ok and addr <> wwwutil.user_home:
  92.         ok = x.setaddr(wwwutil.user_home)
  93.     if not ok and addr <> wwwutil.system_home:
  94.         ok = x.setaddr(wwwutil.system_home)
  95.     if not ok:
  96.         x.close()
  97.         print '*** Nothing in toplevel menu ***'
  98.         return
  99.     #
  100.     try:
  101.         try:
  102.             x.cmdloop()
  103.         except SystemExit:
  104.             pass
  105.     finally:
  106.         wwwutil.save_file(x.bookmarks, bookmarks_file, BOOKMARKS)
  107.         wwwutil.save_file(x.history + [x.cur_addr], \
  108.             history_file, HISTORY)
  109.         wwwutil.save_file(x.places, places_file, PLACES)
  110.  
  111.  
  112. # Class handling the command loop
  113. class WWWCmd(Cmd):
  114.     #
  115.     def __init__(self):
  116.         Cmd.__init__(self)
  117.         self.prompt = 'Which anchor? (h for help) '
  118.         self.cur_addr = ''
  119.         self.cur_data = ''
  120.         self.cur_title = ''
  121.         self.cur_anchors = []
  122.         self.cur_isindex = 0
  123.         self.bookmarks = []
  124.         self.history = []
  125.         self.places = {}
  126.     #
  127.     def close(self):
  128.         pass
  129.     #
  130.     def do_add(self, arg):
  131.         if self.cur_addr in self.bookmarks:
  132.             print '*** Already in list of marks: m',
  133.             print self.bookmarks.index(self.cur_addr)+1
  134.             return
  135.         self.bookmarks.append(self.cur_addr)
  136.         print 'Added as m', len(self.bookmarks)
  137.     do_a = do_add
  138.     #
  139.     def do_back(self, arg):
  140.         if not self.history:
  141.             print '*** No more levels'
  142.             return
  143.         addr = self.history[-1]
  144.         del self.history[-1]
  145.         if not self.setaddr(addr):
  146.             print '*** Lost that link -- try again'
  147.     do_b = do_back
  148.     #
  149.     def do_find(self, arg):
  150.         if not self.cur_isindex:
  151.             print '*** Not an index'
  152.             return
  153.         words = string.split(arg)
  154.         if not words:
  155.             print '*** What do you want to find?'
  156.             return
  157.         scheme, host, port, path, search, anchor = \
  158.             wwwlib.parse_addr(self.cur_addr)
  159.         search = '?' + string.joinfields(words, '+')
  160.         addr = wwwlib.unparse_addr(scheme,host,port,path,search,'')
  161.         self.follow(addr)
  162.     do_f = do_find
  163.     #
  164.     def do_goto(self, arg):
  165.         self.follow(arg)
  166.     do_g = do_goto
  167.     #
  168.     do_h = Cmd.do_help.im_func
  169.     # XXX Very unsatisfactory hack!  It used to read Cmd.do_help but
  170.     # XXX since 0.9.9 that yields an <unbound method> object which
  171.     # XXX can't be passed on transparently to a derived class
  172.     # XXX in this way.  (Maybe Python should be changed?)
  173.     #
  174.     def do_info(self, arg):
  175.         print self.cur_addr
  176.         if self.cur_isindex:
  177.             print '<ISINDEX>'
  178.         if self.cur_title:
  179.             print '<TITLE>' + self.cur_title + '</TITLE>'
  180.     do_i = do_info
  181.     #
  182.     def do_list(self, arg):
  183.         if not self.cur_anchors:
  184.             print '*** No anchors here'
  185.             return
  186.         verbose = (arg == '-v')
  187.         real_stdout = sys.stdout
  188.         pipe = sys.stdout = os.popen('${PAGER-more}', 'w')
  189.         try:
  190.             for i in range(len(self.cur_anchors)):
  191.                 label = `[i+1]`
  192.                 addr = self.cur_anchors[i]
  193.                 if verbose:
  194.                     print label, addr
  195.                     label = ' '*len(label)
  196.                 full = wwwlib.full_addr(self.cur_addr, \
  197.                     addr, self.cur_isindex)
  198.                 if verbose and full <> addr:
  199.                     print label, full
  200.                 if self.places.has_key(full):
  201.                     t = self.places[full][0]
  202.                 else:
  203.                     t = None
  204.                 if t:
  205.                     print label, t
  206.                 elif not verbose:
  207.                     print label, addr
  208.             sys.stdout = real_stdout
  209.         except IOError, msg:
  210.             sys.stdout = real_stdout
  211.             print '*** IOError:', msg
  212.         except KeyboardInterrupt:
  213.             sys.stdout = real_stdout
  214.             print
  215.         sts = pipe.close()
  216.         if sts:
  217.             print '*** Pager exit status:', sts
  218.     do_l = do_list
  219.     #
  220.     def do_mark(self, arg):
  221.         list = self.bookmarks
  222.         verbose = 0
  223.         if arg == '-v':
  224.             verbose = 1
  225.             words = []
  226.         else:
  227.             words = string.split(arg)
  228.         if words:
  229.             try:
  230.                 i = string.atoi(words[0])
  231.             except string.atoi_error:
  232.                 print '*** usage: m(ark) [number]'
  233.                 return
  234.             if 1 <= i <= len(list):
  235.                 self.follow(list[i-1])
  236.             else:
  237.                 print '*** recall index out of range',
  238.                 print '(' + `1` + '...' + `len(list)` + ')'
  239.             return
  240.         for i in range(len(list)):
  241.             label = 'm ' + `i+1`
  242.             addr = list[i]
  243.             title, exits = self.places[addr]
  244.             if title:
  245.                 print label, title
  246.             else:
  247.                 print label, addr
  248.             if not verbose:
  249.                 continue
  250.             label = ' '*len(label)
  251.             if title:
  252.                 print label, addr
  253.             label = label + ' (-->'
  254.             for exit in exits:
  255.                 if i+1 >= len(list) or exit != list[i+1]:
  256.                     t = self.places[exit][0]
  257.                     if t:
  258.                         print label, t + ')'
  259.                     else:
  260.                         print label, exit + ')'
  261.     do_m = do_mark
  262.     #
  263.     def do_places(self, arg):
  264.         real_stdout = sys.stdout
  265.         pipe = sys.stdout = os.popen('${PAGER-more}', 'w')
  266.         try:
  267.             for addr in self.places.keys():
  268.                 print addr
  269.                 title, exits = self.places[addr]
  270.                 if title:
  271.                     print '(' + title + ')'
  272.                 for exit in exits:
  273.                     print '-->', exit
  274.                     t = self.places[exit][0]
  275.                     if t:
  276.                         print '   ', '(' + t + ')'
  277.             sys.stdout = real_stdout
  278.         except IOError, msg:
  279.             sys.stdout = real_stdout
  280.             print '*** IOError:', msg
  281.         except KeyboardInterrupt:
  282.             sys.stdout = real_stdout
  283.             print
  284.         sts = pipe.close()
  285.         if sts:
  286.             print '*** Pager exit status:', sts
  287.     #
  288.     def do_quit(self, arg):
  289.         print '[Goodbye]'
  290.         raise SystemExit
  291.     do_EOF = do_q = do_quit
  292.     #
  293.     def do_recall(self, arg):
  294.         verbose = 0
  295.         hlist = self.history + [self.cur_addr]
  296.         if arg == '-v':
  297.             verbose = 1
  298.             words = []
  299.         else:
  300.             words = string.split(arg)
  301.         if words:
  302.             try:
  303.                 i = string.atoi(words[0])
  304.             except string.atoi_error:
  305.                 print '*** usage: r(ecall) [number]'
  306.                 return
  307.             if 1 <= i <= len(hlist):
  308.                 self.follow(hlist[i-1])
  309.             else:
  310.                 print '*** recall index out of range',
  311.                 print '(' + `1` + '...' + `len(hlist)` + ')'
  312.             return
  313.         for i in range(len(hlist)):
  314.             label = 'r ' + `i+1`
  315.             addr = hlist[i]
  316.             title, exits = self.places[addr]
  317.             if title:
  318.                 print label, title
  319.             else:
  320.                 print label, addr
  321.             if not verbose:
  322.                 continue
  323.             label = ' '*len(label)
  324.             if title:
  325.                 print label, addr
  326.             label = label + ' (-->'
  327.             for exit in exits:
  328.                 if i+1 >= len(hlist) or exit != hlist[i+1]:
  329.                     t = self.places[exit][0]
  330.                     if t:
  331.                         print label, t + ')'
  332.                     else:
  333.                         print label, exit + ')'
  334.     do_r = do_recall
  335.     #
  336.     def do_source(self, arg):
  337.         pipe = os.popen('${PAGER-more}', 'w')
  338.         try:
  339.             pipe.write(self.cur_data)
  340.         except IOError, msg:
  341.             print '*** IOError:', msg
  342.         except KeyboardInterrupt:
  343.             print
  344.         sts = pipe.close()
  345.         if sts:
  346.             print '*** Pager exit status:', sts
  347.     do_s = do_source
  348.     #
  349.     def do_top(self, arg):
  350.         self.show()
  351.     do_t = do_top
  352.     #
  353.     def default(self, line):
  354.         try:
  355.             i = string.atoi(string.strip(line))
  356.         except string.atoi_error:
  357.             if self.cur_isindex:
  358.                 self.do_find(line)
  359.             else:
  360.                 print '*** Unknown command, type h for help'
  361.             return
  362.         if not self.cur_anchors:
  363.             print '*** No anchors here, type u to go up a level'
  364.             return
  365.         if not 1 <= i <= len(self.cur_anchors):
  366.             print '*** Number out of anchor range [1-' + \
  367.                 `len(self.cur_anchors)` + '] (l lists anchors)'
  368.             return
  369.         self.follow(self.cur_anchors[i-1])
  370.     #
  371.     def follow(self, addr):
  372.         parent = self.cur_addr
  373.         if self.setaddr(addr):
  374.             self.history.append(parent)
  375.             exits = self.places[parent][1]
  376.             if self.cur_addr in exits:
  377.                 exits.remove(self.cur_addr)
  378.             exits.append(self.cur_addr)
  379.             self.prompt = self.baseprompt + '(b=back, h=help) '
  380.     #
  381.     def setaddr(self, addr):
  382.         addr = wwwlib.full_addr(self.cur_addr, addr, \
  383.             self.cur_isindex)
  384.         try:
  385.             data = wwwlib.get_document(addr)
  386.         except (wwwlib.BadAddress, IOError), msg:
  387.             print '***', addr, ':', msg
  388.             return 0
  389.         self.cur_addr = addr
  390.         self.cur_data = data
  391.         self.cur_title = ''
  392.         self.cur_anchors = []
  393.         self.cur_isindex = 0
  394.         self.show()
  395.         #
  396.         if not self.places.has_key(self.cur_addr):
  397.             exits = []
  398.         else:
  399.             exits = self.places[self.cur_addr][1]
  400.         self.places[self.cur_addr] = (self.cur_title, exits)
  401.         #
  402.         if self.cur_isindex and self.cur_anchors:
  403.             prompt = 'Keyword or anchor? '
  404.         elif self.cur_isindex:
  405.             prompt = 'Find keyword? '
  406.         elif self.cur_anchors:
  407.             prompt = 'Which anchor? '
  408.         else:
  409.             prompt = 'What now? '
  410.         self.baseprompt = prompt
  411.         self.prompt = prompt + '(q == quit, h == help) '
  412.         return 1
  413.     #
  414.     def show(self):
  415.         pipe = os.popen('${PAGER-more}', 'w')
  416.         fmtr = fmt.WritingFormatter(pipe, PAGE_WIDTH)
  417.         parser = htmllib.FormattingParser(fmtr, \
  418.                               htmllib.NullStylesheet)
  419.         try:
  420.             parser.feed(self.cur_data)
  421.             parser.close()
  422.             pipe.write('\n\n')
  423.         except IOError, msg:
  424.             print '*** IOError:', msg
  425.         except KeyboardInterrupt:
  426.             print
  427.         sts = pipe.close()
  428.         if sts:
  429.             print '*** Pager exit status:', sts
  430.         self.cur_anchors = parser.anchors
  431.         self.cur_title = parser.title
  432.         self.cur_isindex = parser.isindex
  433.  
  434.  
  435. try:
  436.     main()
  437. except KeyboardInterrupt:
  438.     print
  439.     print '[Intr]'
  440.